import socket,select,time,struct
from helpFunc import *
class base():
    def __init__(self,dataPort,numPort,oneLen,packEffectTime,timeoutInter,k):
        self.dataSock = self.numSock = None
        self.oneLen = oneLen
        self.numPort = numPort
        self.dataPort = dataPort
        self.iniSock()
        self.wrietBuf = b''
        self.wrietBuf2 = b''
        self.key = k
        self.sendPos = 0
        self.peerPos = 0
        self.packSendTime = packEffectTime
        self.lastPackCreateTime = time.monotonic()
        self.recvPos = 0   
        self.sendMap = {0:{'data':b'','sendTime':0,'peerGot':False}}
        self.rNet = self.wNet = 0
        self.maxGotLen = self.maxSenLen = 0
        self.timeoutInter = timeoutInter
        self.gotRate = 1
        self.maxAskTime = self.calAskTime()        
        self.lastRecvTime = time.monotonic()
        
    def calAskTime(self):
        if self.gotRate>0.9:
            return 2
        if self.gotRate>0.75:
            return 3
        if self.gotRate>0.5:
            return 4
        if self.gotRate>0.25:
            return 5
        if self.gotRate>0.1:
            return 8
        return 20
            
    def reFreshSendMap(self):
        if self.sendMap[self.sendPos]['data']==b'':
            return
        if time.monotonic()>self.lastPackCreateTime+self.packSendTime:
            self.sendPos+=1
            self.sendMap[self.sendPos] ={'data':b'','sendTime':0,'peerGot':False}
            self.lastPackCreateTime = time.monotonic()
                
    def dealFd(self,fd,e):
        if isWindows:
            rl,wl = fd,e
            if self.dataSock in rl:
                self.dealDataRecv()
            if self.dataSock in wl:
                n = self.dataSock.send(self.wrietBuf)
                self.wNet += n
                self.wrietBuf = self.wrietBuf[n:]     
            if self.numSock in wl:
                n = self.numSock.send(self.wrietBuf2)
                self.wrietBuf2 = self.wrietBuf2[n:]                     
            return
        
        if fd ==self.dataSock.fileno() and e&select.POLLIN:   
            self.dealDataRecv()
            
        elif fd ==self.dataSock.fileno() and e&select.POLLOUT:
            n = self.dataSock.send(self.wrietBuf)
            self.wNet += n
            self.wrietBuf = self.wrietBuf[n:]     
            
        elif fd ==self.numSock.fileno() and e&select.POLLOUT:
            n = self.numSock.send(self.wrietBuf2)
            self.wrietBuf2 = self.wrietBuf2[n:]     
            
    def tellAddBuf(self,l):
        self.wrietBuf2 += struct.pack('i',l)
        
    def rig(self,po): 
        if isWindows:
            wl=[]
            rl = []
            rl.append(self.dataSock)
            if self.wrietBuf:
                wl.append(self.dataSock)
            if self.wrietBuf2:
                wl.append(self.numSock)      
            return rl,wl
        else:
            if self.wrietBuf:
                po.register(self.dataSock, select.POLLIN|select.POLLOUT)
            else:            
                po.register(self.dataSock, select.POLLIN)
            if self.wrietBuf2:
                po.register(self.numSock, select.POLLIN|select.POLLOUT)  
            
    def calWaitTime(self):
        if self.sendMap[self.sendPos]['data'] == b'':
            return int(self.timeoutInter*1000)
        t = self.lastPackCreateTime+self.packSendTime-time.monotonic()
        if t>self.timeoutInter:
            return int(self.timeoutInter*1000)
        t = int(t*1000)
        if t<0:
            t=0
        return t      
    
    def dealDataRecv(self):
        r = self.dataSock.recv(tcpReadLen)
        self.rNet += len(r)
        if len(r)+len(self.sendMap[self.sendPos]['data'])>=self.oneLen:
            self.lastPackCreateTime = time.monotonic()
        pos = 0
        while True:
            ll = self.oneLen-len(self.sendMap[self.sendPos]['data'])
            self.sendMap[self.sendPos]['data'] += r[pos:pos+ll]
            if len(self.sendMap[self.sendPos]['data'])<self.oneLen:
                break
            pos += ll
            self.sendPos += 1
            self.sendMap[self.sendPos] = {'data':b'','sendTime':0,'peerGot':False}   
            
    def iniSock(self):
        add = ('127.0.0.1',self.dataPort)
        s =socket.socket()        
        s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        s.bind(add)
        s.listen(1)
        self.dataSock,b=s.accept()
        s.close()
        self.dataSock.setblocking(False)
        add = ('127.0.0.1',self.numPort)
        s =socket.socket()        
        s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        s.bind(add)
        s.listen(1)
        self.numSock,b=s.accept()
        s.close()    
        self.numSock.setblocking(False)